﻿using System;
using System.Collections.Generic;
using System.Linq;
using kemocard.Scripts.Buff;
using kemocard.Scripts.Card;
using kemocard.Scripts.Common;
using kemocard.Scripts.Hero;
using kemocard.Scripts.MVC;
using kemocard.Scripts.Pawn;

namespace kemocard.Scripts.Module.Battle;

public class BattleCharacter : BaseCharacter, IBattlePawn
{
    int IBattlePawn.MaxHealth
    {
        get => MaxHealth;
        set => MaxHealth = value;
    }

    private int _maxHealth;
    private int _currentHealth;

    public override int MaxHealth
    {
        get => _maxHealth;
        set
        {
            _maxHealth = value;
            CurrentHealth = Math.Clamp(CurrentHealth, 0, _maxHealth);
        }
    }

    public int CurrentHealth
    {
        get => _currentHealth;
        set => _currentHealth = Math.Clamp(value, 0, MaxHealth);
    }

    public List<BaseBattleCard> Deck = [];

    public Dictionary<int, BaseBattleCard> Hand = new()
    {
        { 0, null },
        { 1, null },
        { 2, null },
        { 3, null },
        { 4, null },
    };

    public List<string> Discard = [];

    public List<BaseBattleCard> TempUsedCard = [];

    public const int MaxHandSize = 5;

    public bool IsDead { get; set; }

    int IBattlePawn.PDefense
    {
        get => PDefense;
        set => PDefense = value;
    }

    int IBattlePawn.MDefense
    {
        get => MDefense;
        set => MDefense = value;
    }

    public bool IsSilenced { get; set; }

    public bool IsResetDeck;

    public int Cost;
    public int CanUseCost;
    public int CurrLockedCost;

    public bool IsConfirm;

    public List<BaseBattleCard> UsedCardThisTurn = [];
    public List<BaseBattleCard> UsedCardThisBattle = [];

    public float GetReduction() => Reduction;

    private int _power;
    public int PowerLimit = 100;
    public int UsedSkillCount;
    private List<int> _skillCoolDown = [4];
    private List<int> _skillPowerCost = [100];
    public List<int> SkillCoolDown => _script?.SkillCoolDown ?? _skillCoolDown;
    public List<int> SkillPowerCost => _script?.SkillPowerCost ?? _skillPowerCost;
    public int CurSkillIdx;
    public int CurCoolDown;
    private HeroScript _script;

    public int Power
    {
        get => _power;
        set => _power = Math.Clamp(value, 0, PowerLimit);
    }

    public BattleCharacter(BaseCharacter character)
    {
        if (character == null) return;
        Id = character.Id;
        InitFromConfig(Id);
        Role = character.Role;
        Cards = character.Cards;
        _script = HeroFactory.CreateHero(Id);
        if (_script != null)
        {
            _script.Owner = this;
        }

        GameCore.EventBus.AddEvent(this, CommonEvent.PlayerPropUpdate, OnPropUpdate);
    }

    public int GetHandCount()
    {
        return Hand.Values.Count(card => card != null);
    }

    public void Init()
    {
        CurrentHealth = MaxHealth;
        foreach (var baseCard in Cards)
        {
            Deck.Add(new BaseBattleCard(baseCard));
        }

        // 洗牌
        StaticUtil.Shuffle(Deck);
    }

    public void AddToHand(BaseBattleCard card)
    {
        if (IsDead) return;
        // 找到Hand中为null的位置添加进去
        for (var i = 0; i < Hand.Count; i++)
        {
            if (Hand[i] != null) continue;
            Hand[i] = card;
            break;
        }
    }

    public void DrawCard(int count)
    {
        if (IsDead) return;
        for (int i = 0; i < count; i++)
        {
            if (GetHandCount() >= MaxHandSize)
            {
                return;
            }

            if (Deck.Count == 0 && IsResetDeck == false)
            {
                StaticUtil.Shuffle(Discard);
                foreach (var se in Discard)
                {
                    // 创建新的卡牌变体加到卡组里
                    Deck.Add(new BaseBattleCard(new BaseCard(se)));
                }

                Discard.Clear();
                IsResetDeck = true;
            }

            if (Deck.Count == 0)
            {
                return;
            }

            AddToHand(Deck[0]);
            Deck.RemoveAt(0);
        }
    }

    public void UseCard(string id, List<BasePawn> target)
    {
        if (IsDead) return;
        if (string.IsNullOrWhiteSpace(id) || target == null) return;
        var card = Hand.Values.FirstOrDefault(baseBattleCard => baseBattleCard.Id == id);
        if (card == null) return;
        card.Target = target;
        card.User = this;
        card.UpdateRealTimeValue();
        TempUsedCard.Add(card);
        UpdateCanUseCost();
        GameCore.ControllerMgr.SendUpdate(ControllerType.Battle, CommonEvent.BattleEvent_UseCard, card);
    }

    public void CancelUseCard(string id)
    {
        if (string.IsNullOrWhiteSpace(id)) return;
        var card = Hand.Values.FirstOrDefault(baseBattleCard => baseBattleCard.Id == id);
        if (card == null) return;
        card.Target = null;
        card.User = null;
        card.UpdateRealTimeValue();
        TempUsedCard.Remove(card);
        UpdateCanUseCost();
        GameCore.ControllerMgr.SendUpdate(ControllerType.Battle, CommonEvent.BattleEvent_CancelUseCard, card);
    }

    private void UpdateCanUseCost()
    {
        CanUseCost = Cost - TempUsedCard.Sum(x => x.Cost);
    }

    public override string GetDetailDesc()
    {
        string result = "";
        result +=
            $"{Name}\n{StaticUtil.GetAttributeName(Attribute)}  回复量:{Heal}\n血量:{CurrentHealth}/{MaxHealth}  费用:{CanUseCost}/{Cost}\n物理防御:{PDefense}  魔法防御:{MDefense}\n物理攻击:{PAttack}  魔法攻击:{MAttack}\n";
        return result;
    }

    public void OnPropUpdate(object obj)
    {
        if (obj != this) return;
        CurrentHealth = Math.Min(CurrentHealth, MaxHealth);
        IsDead = CurrentHealth == 0;
        if (IsDead) return;
        foreach (var baseBattleCard in Hand)
        {
            baseBattleCard.Value?.UpdateRealTimeValue();
        }
    }

    public override void Dispose()
    {
        var temp = TempUsedCard.Concat(Deck).Concat(Hand.Values).Concat(UsedCardThisBattle).Concat(UsedCardThisTurn);
        foreach (var card in temp)
        {
            card?.Dispose();
        }

        if (_script != null)
        {
            _script.Owner = null;
        }

        GameCore.EventBus.RemoveObjAllEvents(this);
        base.Dispose();
    }

    public void Dead()
    {
        // 这里只是让编译器开心，实际不会传任何参数
        var data = new object();
        ExecuteBuffs(ref data, BuffTag.BeforeDead);
        IsDead = true;
        CurrentHealth = 0;
    }

    public void UseSkill()
    {
        if (IsDead) return;
        var mod = GameCore.ControllerMgr.GetControllerModel<BattleModel>(ControllerType.Battle);
        if (mod is not { IsInBattle: true, BattlePhase: BattlePhase.UseCard } || IsDead || !CanUseSkill() ||
            CurSkillIdx == 0)
        {
            return;
        }

        var powerCost = 0;
        if (CurSkillIdx <= SkillPowerCost.Count)
        {
            powerCost = SkillPowerCost[CurSkillIdx - 1];
        }

        if (Power < powerCost) return;

        var tempIdx = CurSkillIdx;
        CurSkillIdx = 0;
        CurCoolDown = 0;
        var tempCost = 0;
        if (tempIdx <= SkillPowerCost.Count)
        {
            tempCost = SkillPowerCost[tempIdx - 1];
        }

        Power -= tempCost;
        _script?.UseSkill(this, tempIdx);
        UsedSkillCount++;
        // 刷新一下技能状态
        DoCoolDown(0);
    }

    public bool CanUseSkill()
    {
        return !IsDead && !IsSilenced && (_script?.CanUseSkill(this) ?? false);
    }

    public void DoCoolDown(int cooldownCount)
    {
        if (IsDead) return;
        if (cooldownCount < 0 || CurSkillIdx >= SkillCoolDown.Count) return;
        var temp = CurCoolDown + cooldownCount;
        for (var i = CurSkillIdx; i < SkillCoolDown.Count; i++)
        {
            if (temp >= SkillCoolDown[i])
            {
                CurSkillIdx++;
                temp -= SkillCoolDown[i];
            }
            else
            {
                CurCoolDown = temp;
                break;
            }
        }
    }

    public int GetCurrentCoolDown()
    {
        return CurSkillIdx < 0 || CurSkillIdx >= SkillCoolDown.Count ? 0 : SkillCoolDown[CurSkillIdx];
    }

    public string GetSkillCdDesc()
    {
        var noCharge = SkillCoolDown.Count <= 1;
        var curCooldown = GetCurrentCoolDown();
        var str = "";
        if (noCharge)
        {
            str += curCooldown == 0 ? "已冷却" : $"冷却{curCooldown}";
        }
        else
        {
            str += $"蓄力{CurSkillIdx}\n冷却{curCooldown}";
        }

        return str;
    }

    public void OnFloorChanged(int floor, bool isFinalFloor)
    {
        if (IsDead) return;
        _script?.OnFloorChanged(floor, isFinalFloor);
    }

    public void OnBattleStart()
    {
        if (IsDead) return;
        _script?.OnBattleStart();
    }

    public void OnTurnStart(int turnCount)
    {
        if (IsDead) return;
        _script?.OnTurnStart(turnCount);
    }
}